package com.xzj.mybatis.utils;

import com.xzj.mybatis.annotation.Param;
import com.xzj.mybatis.annotation.TableField;
import com.xzj.mybatis.annotation.TableId;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ProjectName: SpringDemo
 * @Package: com.xzj.mybatis.utils
 * @ClassName: MapperUtil
 * @Author: xzj
 * @Description:
 * @Date: 2022/7/22 16:48
 * @Version: 1.0
 */
public class MapperUtil {

    /**
     * @Author xzj
     * @Description 函数 获取field对应的表字段名称
     * @Date 10:55 2022/7/25
     * @param null
     * @return
     **/
    public static Function<Field, String> keyMapper = declaredField -> {
        String name = declaredField.getName();
        TableField tableField = declaredField.getAnnotation(TableField.class);
        TableId tableId = declaredField.getAnnotation(TableId.class);
        //权限打开
        declaredField.setAccessible(true);
        if (tableField != null) {
            String value = tableField.value();
            if (!"".equals(value.trim())) {
                name = value;
            }
        }
        if (tableId != null) {
            String value = tableId.value();
            if (!"".equals(value.trim())) {
                name = value;
            }
        }
        return fieldToTable(name);
    };

    /**
     * @param declaredFields
     * @return
     * @Author xzj
     * @Description 获取TableField TableField标记的名称
     * @Date 16:49 2022/7/22
     **/
    public static List<String> getMapperNames(Field[] declaredFields) {
        //得到所有字段的名称
        List<String> names = Arrays.stream(declaredFields).filter(declaredField -> {
            TableField tableField = declaredField.getAnnotation(TableField.class);
            TableId tableId = declaredField.getAnnotation(TableId.class);
            return tableField != null || tableId != null;
        }).map(keyMapper).collect(Collectors.toList());
        return names;
    }

    /**
     * @param fieldName
     * @return
     * @Author xzj
     * @Description po中属性字段转表字段名称
     * @Date 9:33 2022/7/25
     **/
    private static String fieldToTable(String fieldName) {
        StringBuilder sb = new StringBuilder();
        char[] chars = fieldName.toCharArray();
        for (char c : chars) {
            //如果有大写字母 添加下划线
            if (c >= 'A' && c <= 'Z') {
                sb.append('_').append(String.valueOf(c).toLowerCase(Locale.ROOT));
                continue;
            }
            sb.append(c);
        }
        return sb.toString();
    }

    /**
     * @param tableName
     * @return
     * @Author xzj
     * @Description 把表字段名称转po字段名 去掉下划线并把下一个字母转大写
     * @Date 9:37 2022/7/25
     **/
    private static String tableToField(String tableName) {
        StringBuilder sb = new StringBuilder();
        char[] chars = tableName.toCharArray();
        boolean b = false;
        for (char c : chars) {
            if ('_' == c) {
                b = true;
                continue;
            }
            if (b) {
                b = false;
                //转大写
                sb.append(String.valueOf(c).toUpperCase(Locale.ROOT));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * @param aClass
     * @param arg    参数
     * @return
     * @Author xzj
     * @Description 返回一个map集合 map中 key为表字段名称 value为参数值
     * @Date 9:21 2022/7/25
     **/
    public static List<Map<String, Object>> mappingEntity(Class<?> aClass, Object arg) {
        Optional.ofNullable(arg).orElseThrow(() -> new RuntimeException("参数不能为null"));
        Field[] declaredFields = aClass.getDeclaredFields();
        List<Field> fields = Arrays.stream(declaredFields).filter(declaredField -> {
            TableField tableField = declaredField.getAnnotation(TableField.class);
            TableId tableId = declaredField.getAnnotation(TableId.class);
            return tableField != null || tableId != null;
        }).collect(Collectors.toList());

        if (arg instanceof List) {
            List argList = (List) arg;
            List<Map<String, Object>> list = new ArrayList<>(argList.size());
            for (Object x : argList) {
                convert(aClass, fields, list, x);
            }
            return list;
        }
        List<Map<String, Object>> list = new ArrayList<>(2);
        convert(aClass, fields, list, arg);
        return list;
    }

    /**
     * @param aClass 类型 用来校验
     * @param fields 表字段
     * @param list   存放结果集list
     * @param obj    参数对象
     * @return
     * @Author xzj
     * @Description
     * @Date 11:47 2022/7/25
     **/
    private static void convert(Class<?> aClass, List<Field> fields, List<Map<String, Object>> list, Object obj) {
        if (aClass != obj.getClass()) {
            throw new RuntimeException(String.format("参数异常%s不能转换为%s", obj.getClass(), aClass));
        }
        Map<String, Object> map = fields.stream().collect(Collectors.groupingBy(keyMapper, HashMap::new,Collectors.reducing(null,declaredField -> {
            declaredField.setAccessible(true);
            try {
                return declaredField.get(obj);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        },(v1,v2)->v2)));
        list.add(map);
    }

    /**
     * @param sql
     * @param list
     * @param objectMap
     * @return
     * @Author xzj
     * @Description 解析转换 #{}表达式
     * @Date 14:54 2022/7/25
     **/
    public static String conversion(String sql, List<Object> list, Map<String, Object> objectMap) {
        StringBuilder sb = new StringBuilder(sql.length());
        int right = 0;
        for (int i = 0; i < sql.length(); i++) {
            char c = sql.charAt(i);
            if (c == '#') {
                //找下一个 }
                for (int j = i + 2; j < sql.length(); j++) {
                    if (sql.charAt(j) == '}') {
                        //添加结果
                        list.add(objectMap.get(sql.substring(i + 2, j)));
                        i = j;
                        sb.append('?');
                        break;
                    }
                }
                continue;
            }
            sb.append(c);
        }
        return sb.toString();
    }

    /**
     * @param method
     * @param args
     * @return
     * @Author xzj
     * @Description 方法参数设置了@Param
     * @Date 20:45 2022/7/25
     **/
    public static Map<String, Object> mappingParam(Method method, Object[] args) {
        Map<String, Object> map = new HashMap<>(args.length * 2);
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            String name = parameters[i].getName();
            Param param = parameters[i].getAnnotation(Param.class);
            if (param != null) {
                String value = param.value();
                if (!"".equals(value.trim())) {
                    name = value;
                }
            }
            map.put(name, args[i]);
        }
        return map;
    }

    /**
     * @Author xzj
     * @Description 获取实体类上的id
     * @Date 15:48 2022/7/26
     * @param aClass
     * @return
     **/
    public static String getTableIdName(Class<? extends Type> aClass) {
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            TableId tableId = declaredField.getAnnotation(TableId.class);
            if(tableId != null){
                String value = tableId.value();
                if(!"".equals(value.trim())){
                    return value;
                }
                return declaredField.getName();
            }
        }
        return null;
    }
}
